home *** CD-ROM | disk | FTP | other *** search
/ The Atari Compendium / The Atari Compendium (Toad Computers) (1994).iso / files / umich / network / ka9q / ka9q_src.arc / TELNET.C < prev    next >
C/C++ Source or Header  |  1988-07-28  |  9KB  |  485 lines

  1. #include <stdio.h>
  2. #include "global.h"
  3. #include "mbuf.h"
  4. #include "timer.h"
  5. #include "internet.h"
  6. #include "icmp.h"
  7. #include "netuser.h"
  8. #include "tcp.h"
  9. #include "telnet.h"
  10. #include "session.h"
  11.  
  12. extern int ttyflow;        /* DG2KK: flow control */
  13.  
  14. extern char nospace[];
  15. extern char badhost[];
  16. int refuse_echo = 0;
  17. int unix_line_mode = 0;    /* if true turn <cr> to <nl> when in line mode */
  18.  
  19. #ifdef    DEBUG
  20. char *t_options[] = {
  21.     "Transmit Binary",
  22.     "Echo",
  23.     "",
  24.     "Suppress Go Ahead",
  25.     "",
  26.     "Status",
  27.     "Timing Mark"
  28. };
  29. #endif
  30.  
  31. /* Execute user telnet command */
  32. int
  33. dotelnet(argc,argv)
  34. int argc;
  35. char *argv[];
  36. {
  37.     void t_state(),rcv_char(),tn_tx();
  38.     char *inet_ntoa();
  39.     int32 resolve();
  40.     int send_tel();
  41.         int unix_send_tel();
  42.     struct session *s;
  43.     struct telnet *tn;
  44.     struct tcb *tcb;
  45.     struct socket lsocket,fsocket;
  46.  
  47.  
  48.     lsocket.address = ip_addr;
  49.     lsocket.port = lport++;
  50.     if((fsocket.address = resolve(argv[1])) == 0){
  51.         printf(badhost,argv[1]);
  52.         return 1;
  53.     }
  54.     if(argc < 3)
  55.         fsocket.port = TELNET_PORT;
  56.     else
  57.         fsocket.port = atoi(argv[2]);
  58.  
  59.     /* Allocate a session descriptor */
  60.     if((s = newsession()) == NULLSESSION){
  61.         printf("Too many sessions\n");
  62.         return 1;
  63.     }
  64.     if((s->name = malloc((unsigned)strlen(argv[1])+1)) != NULLCHAR)
  65.         strcpy(s->name,argv[1]);
  66.     s->type = TELNET;
  67.     if ((refuse_echo == 0) && (unix_line_mode != 0)) {
  68.         s->parse = unix_send_tel;
  69.     } else {
  70.         s->parse = send_tel;
  71.     }
  72.     current = s;
  73.  
  74.     /* Create and initialize a Telnet protocol descriptor */
  75.     if((tn = (struct telnet *)calloc(1,sizeof(struct telnet))) == NULLTN){
  76.         printf(nospace);
  77.         s->type = FREE;
  78.         return 1;
  79.     }
  80.     tn->session = s;    /* Upward pointer */
  81.     tn->state = TS_DATA;
  82.     s->cb.telnet = tn;    /* Downward pointer */
  83.  
  84.     tcb = open_tcp(&lsocket,&fsocket,TCP_ACTIVE,0,
  85.      rcv_char,tn_tx,t_state,0,(char *)tn);
  86.  
  87.     tn->tcb = tcb;    /* Downward pointer */
  88.     go();
  89.     return 0;
  90. }
  91.  
  92. /* Process typed characters */
  93. int
  94. unix_send_tel(buf,n)
  95. char *buf;
  96. int16 n;
  97. {
  98.     int i;
  99.  
  100.     for (i=0; (i<n) && (buf[i] != '\r'); i++)
  101.         ;
  102.     if (buf[i] == '\r') {
  103.         buf[i] = '\n';
  104.         n = i+1;
  105.     }
  106.     send_tel(buf,n);
  107. }
  108. int
  109. send_tel(buf,n)
  110. char *buf;
  111. int16 n;
  112. {
  113.     struct mbuf *bp,*qdata();
  114.     if(current == NULLSESSION || current->cb.telnet == NULLTN
  115.      || current->cb.telnet->tcb == NULLTCB)
  116.         return;
  117.     /* If we're doing our own echoing and recording is enabled, record it */
  118.     if(!current->cb.telnet->remote[TN_ECHO] && current->record != NULLFILE)
  119.         fwrite(buf,1,n,current->record);
  120.     bp = qdata(buf,n);
  121.     send_tcp(current->cb.telnet->tcb,bp);
  122. }
  123.  
  124. /* Process incoming TELNET characters */
  125. int
  126. tel_input(tn,bp)
  127. register struct telnet *tn;
  128. struct mbuf *bp;
  129. {
  130.     char c;
  131.     int ci;
  132.     void doopt(),dontopt(),willopt(),wontopt(),answer();
  133.     FILE *record;
  134.     char *memchr();
  135.  
  136.     /* Optimization for very common special case -- no command chars */
  137.     if(tn->state == TS_DATA){
  138.         while(bp != NULLBUF && memchr(bp->data,IAC,bp->cnt) == NULLCHAR){
  139.             fwrite(bp->data,1,bp->cnt,stdout);
  140.             if((record = tn->session->record) != NULLFILE)
  141.                 fwrite(bp->data,1,bp->cnt,record);
  142.             bp = free_mbuf(bp);
  143.         }
  144.     }
  145.  
  146.     while(pullup(&bp,&c,1) == 1){
  147.         ci = c & 0xff;
  148.         switch(tn->state){
  149.         case TS_DATA:
  150.             if(ci == IAC){
  151.                 tn->state = TS_IAC;
  152.             } else {
  153.                 if(!tn->remote[TN_TRANSMIT_BINARY])
  154.                     c &= 0x7f;
  155.                 if(c != '\0')    /* Don't screw up ANSI driver */
  156.                     putchar(c);
  157.                 if((record = tn->session->record) != NULLFILE)
  158.                     putc(c,record);
  159.             }
  160.             break;
  161.         case TS_IAC:
  162.             switch(ci){
  163.             case WILL:
  164.                 tn->state = TS_WILL;
  165.                 break;
  166.             case WONT:
  167.                 tn->state = TS_WONT;
  168.                 break;
  169.             case DO:
  170.                 tn->state = TS_DO;
  171.                 break;
  172.             case DONT:
  173.                 tn->state = TS_DONT;
  174.                 break;
  175.             case IAC:
  176.                 putchar(c);
  177.                 tn->state = TS_DATA;
  178.                 break;
  179.             default:
  180.                 tn->state = TS_DATA;
  181.                 break;
  182.             }
  183.             break;
  184.         case TS_WILL:
  185.             willopt(tn,ci);
  186.             tn->state = TS_DATA;
  187.             break;
  188.         case TS_WONT:
  189.             wontopt(tn,ci);
  190.             tn->state = TS_DATA;
  191.             break;
  192.         case TS_DO:
  193.             doopt(tn,ci);
  194.             tn->state = TS_DATA;
  195.             break;
  196.         case TS_DONT:
  197.             dontopt(tn,ci);
  198.             tn->state = TS_DATA;
  199.             break;
  200.         }
  201.     }
  202. }
  203.  
  204. /* Telnet receiver upcall routine */
  205. void
  206. rcv_char(tcb,cnt)
  207. register struct tcb *tcb;
  208. int16 cnt;
  209. {
  210.     struct mbuf *bp;
  211.     struct telnet *tn;
  212.     FILE *record;
  213.  
  214.     if((tn = (struct telnet *)tcb->user) == NULLTN){
  215.         /* Unknown connection; ignore it */
  216.         return;
  217.     }
  218.     /* Hold output if we're not the current session */
  219.     if(mode != CONV_MODE || current == NULLSESSION
  220.      || current->type != TELNET || current->cb.telnet != tn)
  221.         return;
  222.  
  223.     /* DG2KK: hold output during keyboard input */
  224.     if (ttyflow == 0)
  225.         return;
  226.  
  227.     if(recv_tcp(tcb,&bp,cnt) > 0)
  228.         tel_input(tn,bp);
  229.  
  230.     fflush(stdout);
  231.     if((record = tn->session->record) != NULLFILE)
  232.         fflush(record);
  233. }
  234. /* Handle transmit upcalls. Used only for file uploading */
  235. void
  236. tn_tx(tcb,cnt)
  237. struct tcb *tcb;
  238. int16 cnt;
  239. {
  240.     struct telnet *tn;
  241.     struct session *s;
  242.     struct mbuf *bp;
  243.     int size;
  244.  
  245.     if((tn = (struct telnet *)tcb->user) == NULLTN
  246.      || (s = tn->session) == NULLSESSION
  247.      || s->upload == NULLFILE)
  248.         return;
  249.     if((bp = alloc_mbuf(cnt)) == NULLBUF)
  250.         return;
  251.     if((size = fread(bp->data,1,cnt,s->upload)) > 0){
  252.         bp->cnt = (int16)size;
  253.         send_tcp(tcb,bp);
  254.     } else {
  255.         free_p(bp);
  256.     }
  257.     if(size != cnt){
  258.         /* Error or end-of-file */
  259.         fclose(s->upload);
  260.         s->upload = NULLFILE;
  261.         free(s->ufile);
  262.         s->ufile = NULLCHAR;
  263.     }
  264. }
  265.  
  266. /* State change upcall routine */
  267. void
  268. t_state(tcb,old,new)
  269. register struct tcb *tcb;
  270. char old,new;
  271. {
  272.     struct telnet *tn;
  273.     char notify = 0;
  274.     extern char *tcpstates[];
  275.     extern char *reasons[];
  276.     extern char *unreach[];
  277.     extern char *exceed[];
  278.  
  279.     /* Can't add a check for unknown connection here, it would loop
  280.      * on a close upcall! We're just careful later on.
  281.      */
  282.     tn = (struct telnet *)tcb->user;
  283.  
  284.     if(current != NULLSESSION && current->type == TELNET && current->cb.telnet == tn)
  285.         notify = 1;
  286.  
  287.     switch(new){
  288.     case CLOSE_WAIT:
  289.         if(notify)
  290.             printf("%s\n",tcpstates[new]);
  291.         close_tcp(tcb);
  292.         break;
  293.     case CLOSED:    /* court adjourned */
  294.         if(notify){
  295.             printf("%s (%s",tcpstates[new],reasons[tcb->reason]);
  296.             if(tcb->reason == NETWORK){
  297.                 switch(tcb->type){
  298.                 case DEST_UNREACH:
  299.                     printf(": %s unreachable",unreach[tcb->code]);
  300.                     break;
  301.                 case TIME_EXCEED:
  302.                     printf(": %s time exceeded",exceed[tcb->code]);
  303.                     break;
  304.                 }
  305.             }
  306.             printf(")\n");
  307.             cmdmode();
  308.         }
  309.         del_tcp(tcb);
  310.         if(tn != NULLTN)
  311.             free_telnet(tn);
  312.         break;
  313.     default:
  314.         if(notify)
  315.             printf("%s\n",tcpstates[new]);
  316.         break;
  317.     }
  318.     fflush(stdout);
  319. }
  320. /* Delete telnet structure */
  321. static
  322. free_telnet(tn)
  323. struct telnet *tn;
  324. {
  325.     if(tn->session != NULLSESSION)
  326.         freesession(tn->session);
  327.  
  328.     if(tn != NULLTN)
  329.         free((char *)tn);
  330. }
  331.  
  332. /* The guts of the actual Telnet protocol: negotiating options */
  333. static
  334. void
  335. willopt(tn,opt)
  336. struct telnet *tn;
  337. int opt;
  338. {
  339.     int ack;
  340.     void answer();
  341.  
  342. #ifdef    DEBUG
  343.     printf("recv: will ");
  344.     if(opt <= NOPTIONS)
  345.         printf("%s\n",t_options[opt]);
  346.     else
  347.         printf("%u\n",opt);
  348. #endif
  349.     
  350.     switch(opt){
  351.     case TN_TRANSMIT_BINARY:
  352.     case TN_ECHO:
  353.     case TN_SUPPRESS_GA:
  354.         if(tn->remote[opt] == 1)
  355.             return;        /* Already set, ignore to prevent loop */
  356.         if(opt == TN_ECHO){
  357.             if(refuse_echo){
  358.                 /* User doesn't want to accept */
  359.                 ack = DONT;
  360.                 break;
  361.             } else
  362.                 raw();        /* Put tty into raw mode */
  363.         }
  364.         tn->remote[opt] = 1;
  365.         ack = DO;            
  366.         break;
  367.     default:
  368.         ack = DONT;    /* We don't know what he's offering; refuse */
  369.     }
  370.     answer(tn,ack,opt);
  371. }
  372. static
  373. void
  374. wontopt(tn,opt)
  375. struct telnet *tn;
  376. int opt;
  377. {
  378.     void answer();
  379.  
  380. #ifdef    DEBUG
  381.     printf("recv: wont ");
  382.     if(opt <= NOPTIONS)
  383.         printf("%s\n",t_options[opt]);
  384.     else
  385.         printf("%u\n",opt);
  386. #endif
  387.     if(opt <= NOPTIONS){
  388.         if(tn->remote[opt] == 0)
  389.             return;        /* Already clear, ignore to prevent loop */
  390.         tn->remote[opt] = 0;
  391.         if(opt == TN_ECHO)
  392.             cooked();    /* Put tty into cooked mode */
  393.     }
  394.     answer(tn,DONT,opt);    /* Must always accept */
  395. }
  396. static
  397. void
  398. doopt(tn,opt)
  399. struct telnet *tn;
  400. int opt;
  401. {
  402.     void answer();
  403.     int ack;
  404.  
  405. #ifdef    DEBUG
  406.     printf("recv: do ");
  407.     if(opt <= NOPTIONS)
  408.         printf("%s\n",t_options[opt]);
  409.     else
  410.         printf("%u\n",opt);
  411. #endif
  412.     switch(opt){
  413. #ifdef    FUTURE    /* Use when local options are implemented */
  414.         if(tn->local[opt] == 1)
  415.             return;        /* Already set, ignore to prevent loop */
  416.         tn->local[opt] = 1;
  417.         ack = WILL;
  418.         break;
  419. #endif
  420.     default:
  421.         ack = WONT;    /*